﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;
using YJKGridTopologyCal.Algorithm;
using YJKGridTopologyCal.Geometries;

namespace YJKGridTopologyCal.Noding.Snapround
{
	public class SimpleSnapRounder : INoder
	{
		public SimpleSnapRounder(PrecisionModel pm)
		{
			this._li = new RobustLineIntersector
			{
				PrecisionModel = pm
			};
			this._scaleFactor = pm.Scale;
		}

		public IList<ISegmentString> GetNodedSubstrings()
		{
			return NodedSegmentString.GetNodedSubstrings(this._nodedSegStrings);
		}

		public void ComputeNodes(IList<ISegmentString> inputSegmentStrings)
		{
			this._nodedSegStrings = inputSegmentStrings;
			this.SnapRound(inputSegmentStrings, this._li);
		}

		private void SnapRound(IList<ISegmentString> segStrings, LineIntersector li)
		{
			IList<Coordinate> snapPts = SimpleSnapRounder.FindInteriorIntersections(segStrings, li);
			this.ComputeSnaps(segStrings, snapPts);
			this.ComputeVertexSnaps(segStrings);
		}

		private static IList<Coordinate> FindInteriorIntersections(IList<ISegmentString> segStrings, LineIntersector li)
		{
			InteriorIntersectionFinderAdder interiorIntersectionFinderAdder = new InteriorIntersectionFinderAdder(li);
			new MCIndexNoder(interiorIntersectionFinderAdder).ComputeNodes(segStrings);
			return interiorIntersectionFinderAdder.InteriorIntersections;
		}

		private void ComputeSnaps(IEnumerable<ISegmentString> segStrings, ICollection<Coordinate> snapPts)
		{
			foreach (ISegmentString segmentString in segStrings)
			{
				INodableSegmentString ss = (INodableSegmentString)segmentString;
				this.ComputeSnaps(ss, snapPts);
			}
		}

		private void ComputeSnaps(INodableSegmentString ss, IEnumerable<Coordinate> snapPts)
		{
			foreach (Coordinate pt in snapPts)
			{
				HotPixel hotPixel = new HotPixel(pt, this._scaleFactor, this._li);
				for (int i = 0; i < ss.Count - 1; i++)
				{
					hotPixel.AddSnappedNode(ss, i);
				}
			}
		}

		public void ComputeVertexSnaps(IList<ISegmentString> edges)
		{
			foreach (ISegmentString segmentString in edges)
			{
				INodableSegmentString e = (INodableSegmentString)segmentString;
				foreach (ISegmentString segmentString2 in edges)
				{
					INodableSegmentString e2 = (INodableSegmentString)segmentString2;
					this.ComputeVertexSnaps(e, e2);
				}
			}
		}

		private void ComputeVertexSnaps(INodableSegmentString e0, INodableSegmentString e1)
		{
			Coordinate[] coordinates = e0.Coordinates;
			Coordinate[] coordinates2 = e1.Coordinates;
			for (int i = 0; i < coordinates.Length - 1; i++)
			{
				HotPixel hotPixel = new HotPixel(coordinates[i], this._scaleFactor, this._li);
				for (int j = 0; j < coordinates2.Length - 1; j++)
				{
					if ((e0 != e1 || i != j) && hotPixel.AddSnappedNode(e1, j))
					{
						e0.AddIntersection(coordinates[i], i);
					}
				}
			}
		}

		private readonly LineIntersector _li;

		private readonly double _scaleFactor;

		private IList<ISegmentString> _nodedSegStrings;
	}
}
